﻿using System.Collections.Generic;
using System.Linq;
using C3.XNA;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using RpgXna.Model.Helpers;
using RpgXna.Model.Interfaces.ContextMenu.NavigationBehaviors;
using RpgXna.Model.Interfaces.InterfacesManagement;
using RpgXna.Model.Menu;
using RpgXna.Model.Menu.MenuBehaviors;
using RpgXna.Model.XnaClassesWrappers;

namespace RpgXna.Model.Interfaces.ContextMenu
{
    public class ContextMenu : IInterface
    {
        private readonly IInputManager _input;
        private readonly IInterfaceComponent _interface;
        private readonly List<IContextMenuBehavior> _options;
        private List<IContextMenuNavigateBehavior> _ctxNavBehaoviors;
        private SpriteFont _font;
        private Vector2 _position;
        private Rectangle _ctxMenuBackground;

        public ContextMenu(IInterfaceComponent ifc, IInputManager input)
        {
            CreateContextMenuBehaviors();
            _input = input;
            _options = new List<IContextMenuBehavior>();
            _interface = ifc;
            _input.LeftMouseButtonClick += InputLeftMouseButtonClick;
        }

        public void ConfigureOptions(Vector2 position, params IContextMenuBehavior[] incommingOptions)
        {
            if (!_interface.IsVisible)
            {
                _position = position;
                _options.Clear();
                _options.AddRange(incommingOptions);
                _interface.Show();
            }
        }

        public void Draw(SpriteBatch sb)
        {
            if (!_interface.IsVisible) return;

            sb.FillRectangle(_ctxMenuBackground, Color.Gray);

            //options layout with first positively offseted to Y+50
            for (int i = 0; i < _options.Count; i++)
            {
                var optionHolder = _options[i].Box;
                sb.FillRectangle(optionHolder, Color.Orange);
                if (_options[i].IsSelected)
                {
                    sb.DrawRectangle(optionHolder, Color.Black, 2);
                }
                sb.DrawString(_font, _options[i].ItemName, new Vector2(optionHolder.X + 5, optionHolder.Y + 3), Color.Black, 0f, Vector2.Zero, 1f, SpriteEffects.None, 0);
            }

        }

        public void Load(ContentManager cm)
        {
            _font = cm.Load<SpriteFont>("Arial12");
        }

        public void Update(IKeyboardStateWrapper kbs)
        {
            UpdateHolder();

            EvaluateNavigationBehaviors(kbs);
        }

        private void EvaluateNavigationBehaviors(IKeyboardStateWrapper kbs)
        {
            //execute all navigation behaviors
            foreach (IContextMenuNavigateBehavior ctb in _ctxNavBehaoviors)
            {
                ctb.Execute(_options.Cast<INavigationSelectable>().ToList(), kbs);
            }
        }

        private void UpdateHolder()
        {
            //menu layout, width fixed, height = 30 * options.count + 5 margin top + 5 margin bottom = 20 + 30*options
            _ctxMenuBackground = new Rectangle((int)_position.X, (int)_position.Y, 200, 10 + 30 * _options.Count);

            //for each options, calculate holder
            for (int i = 0; i < _options.Count; i++)
            {
                var optionHolder = new Rectangle((int)_position.X + 5, ((int)_position.Y + 5) + i * 30, 190, 25);
                _options[i].Box = optionHolder;
            }
        }

        private void CreateContextMenuBehaviors()
        {
            _ctxNavBehaoviors = new List<IContextMenuNavigateBehavior>
                                    {
                                        new ContextMenuNavigateDownBehavior(() => _interface.IsVisible),
                                        new ContextMenuNavigationUpBehavior(() => _interface.IsVisible),
                                        new ContextMenuValidateBehavior(() => _interface.IsVisible,
                                                                        Hide)
                                    };
        }

        private void InputLeftMouseButtonClick(MouseState state)
        {
            if (!_interface.IsVisible) return;
            foreach (ContextMenuItem mb in _options)
            {
                if (mb.Box.Contains(state.X, state.Y))
                {
                    mb.Execute();
                   Hide();
                    break;
                }
            }
        }

        public bool IsVisible
        {
            get { return _interface.IsVisible; }
        }

        public int Priority
        {
            get { return _interface.Priority; }
        }

        public void Show()
        {
            _interface.Show();
        }

        public void Hide()
        {
            _interface.Hide();
        }
    }
}